package com.qws.xprinter.flutter_xprinter

import android.Manifest
import android.app.PendingIntent
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbManager
import android.os.Build
import android.util.Log
import android.widget.Toast
import androidx.annotation.NonNull
import androidx.annotation.RequiresApi
import androidx.fragment.app.FragmentActivity
import com.hh.node.UsbReceiver
import com.permissionx.guolindev.PermissionX
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.reactivex.rxjava3.core.Flowable
import net.posprinter.POSConnect
import java.util.concurrent.TimeUnit


/** FlutterXprinterPlugin */
class FlutterXprinterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
    /// The MethodChannel that will the communication between Flutter and native Android
    ///
    /// This local reference serves to register the plugin with the Flutter Engine and unregister it
    /// when the Flutter Engine is detached from the Activity
    private val GPS_ACTION = "android.location.PROVIDERS_CHANGED"
    private lateinit var channel: MethodChannel
    private lateinit var binding: ActivityPluginBinding
    private lateinit var bluetoothAdapter: BluetoothAdapter

    private lateinit var usbManager: UsbManager
    private var usbDevice: UsbDevice? = null
    private lateinit var usbReceiver: UsbReceiver

    companion object {
        const val ACTION_USB_PERMISSION = "com.qws.xprinter.USB_PERMISSION"
    }

    private val mBroadcastReceiver: BroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            val action = intent.action
            if (BluetoothDevice.ACTION_FOUND == action) {
                val btd = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
                if (btd!!.bondState != BluetoothDevice.BOND_BONDED) {
                    var name = btd.name
                    if (name == null) name = "none"
                    channel.invokeMethod(
                        "unpaired",
                        mapOf("isMatching" to false, "name" to name, "mac" to btd.address)
                    )
                }
            }
        }
    }

    override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
        channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_xprinter")
        channel.setMethodCallHandler(this)

        App.get().channel = channel
    }

    @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
    override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
        if (call.method == "getPlatformVersion") {
            result.success("Android ${android.os.Build.VERSION.RELEASE}")
        } else if (call.method == "scanBluetoothDevices") {
            requestPermissions()
        } else if (call.method == "stopDiscovery") {
            if (bluetoothAdapter != null) {
                bluetoothAdapter.cancelDiscovery()
            }
        } else if (call.method == "scanUsbDevices") {
            val list = POSConnect.getUsbDevice(binding.activity)
            val usbList = mutableListOf<Map<String, String?>>()
            list.forEach {
                val map = mutableMapOf<String, String?>()
                map["deviceName"] = it.deviceName
                map["productName"] = it.productName
                usbList.add(map)
            }

            channel.invokeMethod(
                "usbList",
                usbList
            )
        } else if (call.method == "sendPrintTask") {
            if (call.arguments is Map<*, *>) {
                val args = call.arguments as Map<*, *>
                val bytes = args["bytes"] as List<Int>
                val connType = args["connType"] as Int
                val deviceType = args["deviceType"] as Int
                var address = args["address"] as String
                PrinterManager.sendPrintTask(deviceType, connType, address, bytes)
            }
        } else if (call.method == "connect") {
            if (call.arguments is Map<*, *>) {
                val args = call.arguments as Map<*, *>
                val connType = args["connType"] as Int
                val deviceType = args["deviceType"] as Int
                val address = args["address"] as String
                PrinterManager.connect(deviceType, connType, address)
            }
        } else if (call.method == "disconnect") {
            if (call.arguments is Map<*, *>) {
                val args = call.arguments as Map<*, *>
                val address = args["address"] as String
                PrinterManager.disconnect(address)
            }
        } else {
            result.notImplemented()
        }
    }

    override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
        channel.setMethodCallHandler(null)
    }

    override fun onAttachedToActivity(binding: ActivityPluginBinding) {
        this.binding = binding
        bluetoothAdapter =
            (binding.activity.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager).adapter
        val intentFilter = IntentFilter()
        intentFilter.addAction(BluetoothDevice.ACTION_FOUND)
        intentFilter.addAction(GPS_ACTION)
        binding.activity.registerReceiver(mBroadcastReceiver, intentFilter)

        initUsbManager(binding)
    }

    private fun initUsbManager(binding: ActivityPluginBinding) {
        // 初始化USB管理器
        usbManager = binding.activity.getSystemService(Context.USB_SERVICE) as UsbManager
        // 初始化并注册USB广播接收器
        usbReceiver = UsbReceiver()
        usbReceiver.setUsbDeviceListener(object : UsbReceiver.UsbDeviceListener{
            override fun onDeviceAttached(device: UsbDevice) {
                usbDevice = device
                channel.invokeMethod(
                    "usbDeviceAttached",
                    mapOf("deviceName" to device.deviceName, "productName" to device.productName)
                )
                requestUsbPermission(device)
                Log.i("FlutterXprinterPlugin", "onDeviceAttached : ${device.deviceName}")
            }

            override fun onDeviceDetached(device: UsbDevice) {
                channel.invokeMethod(
                    "usbDeviceDetached",
                    mapOf("deviceName" to device.deviceName, "productName" to device.productName)
                )
                Log.i("FlutterXprinterPlugin", "onDeviceDetached : ${device.deviceName}")
            }

            override fun onDevicePermissionGranted(device: UsbDevice) {
                Log.i("FlutterXprinterPlugin", "onDevicePermissionGranted : ${device.deviceName}")
            }

        })

        val filter = IntentFilter().apply {
            addAction(ACTION_USB_PERMISSION)
            addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
            addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
        }
        binding.activity.registerReceiver(usbReceiver, filter)
    }

    private fun requestUsbPermission(device: UsbDevice) {
        // 检查是否已有权限
        if (usbManager.hasPermission(device)) {
            Log.d("USB", "已有USB设备权限: ${device.deviceName}")
            Toast.makeText(binding.activity, "已有USB设备权限", Toast.LENGTH_SHORT).show()
            return
        }
        // 创建权限请求的PendingIntent
        val permissionIntent = PendingIntent.getBroadcast(
            binding.activity, 0, Intent(ACTION_USB_PERMISSION), 0
        )
        // 请求USB权限
        usbManager.requestPermission(device, permissionIntent)
    }

    private fun requestPermissions() {
        val ps = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            listOf(
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.BLUETOOTH_SCAN,
                Manifest.permission.BLUETOOTH_CONNECT,
                Manifest.permission.BLUETOOTH_ADVERTISE
            )
        } else {
            listOf(
                Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION
            )
        }

        PermissionX.init(binding.activity as FragmentActivity)
            .permissions(ps)
            .request { allGranted, _, _ ->
                if (allGranted) {
                    searchBTDevices()
                }
            }

    }

    private fun searchBTDevices() {
        val devices: Set<BluetoothDevice> = bluetoothAdapter.bondedDevices
        val list = mutableListOf<Map<String, Any>>()
        devices.forEach {
            val map = mutableMapOf<String, Any>()
            val name = it.name ?: "None"
            map["isMatching"] = true
            map["name"] = name
            map["mac"] = it.address
            list.add(map)
        }

        channel.invokeMethod(
            "paired",
            list
        )

        if (bluetoothAdapter.isDiscovering) {
            bluetoothAdapter.cancelDiscovery()
        }
        Flowable.timer(300, TimeUnit.MILLISECONDS)
            .subscribe {
                bluetoothAdapter.startDiscovery()
            }
        bluetoothAdapter.cancelDiscovery()
    }

    private fun Array<out Int>.toByteArray(): ByteArray {
        return ByteArray(size) { index -> this[index].toByte() }
    }

    override fun onDetachedFromActivityForConfigChanges() {
    }

    override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
    }

    override fun onDetachedFromActivity() {
    }
}
